package visualcbir;

import visualcbir.format.IPrintable;
import visualcbir.decorators.FunDetailsOnDemand;
import visualcbir.decorators.FunOptions;
import visualcbir.decorators.FunZoom;
import visualcbir.decorators.Functionality;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JViewport;
import visualcbir.util.ComponentUtils;

/**
 *
 * @author sheila
 */
public class PnlView extends JComponent implements IPrintable{
    private View oView;    
    private HashMap<String,Functionality> aoFunctionalities;
    private boolean hasComponentChanged;    
    
    public PnlView(View poView) {
        hasComponentChanged=true;
        this.oView=poView; //s/ this.setNewView(poView);
        this.oView.computeViewDimension();
        this.addListenersAdapters();
        this.addFunctionalities();
    }
    
    public void addListenersAdapters(){
        this.addComponentListener(new ComponentAdapter(){
            @Override
            public void componentResized(ComponentEvent evt) {
                // the component is not considered resized if only o scrol bar shows more.
                // the panel inside scroll have to have a diferent size in order hasComponentChanged changes (enter if in paintComponent)
                System.out.println("component  Resized");
                hasComponentChanged = true; //when the component size changes or when the view to show changes too - needs update.
                repaint();                
        }});
    }
    /**
     * On this function the points are recomputed (hasComponentChanged=true) and the panel is repainted.
     * hasComponentChanged is true when this component is resized or when the structure changes.
     * If no one of this situations happens (for example when scrolling) then
     * the locations does not need to be recomputed, just the panel must be repainted.
     * @param g
     */
    @Override
    protected void paintComponent(Graphics g){
        Dimension dimReal = ComponentUtils.recomputeComponentDimensionsByView( this, this.oView.getViewDimension() );
        if(hasComponentChanged){
            hasComponentChanged=false;      
            this.oView.setCenterPoint(Math.round( dimReal.width/2 ), Math.round(dimReal.height/2));
            this.oView.update(null, null);            
            // When the panel is resized. it must not be aplied on scrol (outside this if)
            Dimension dimAvailable = this.getVisibleRect().getSize();
            ComponentUtils.centerJViewPort(dimReal, dimAvailable, (JViewport)this.getParent() );
            //ComponentUtils.centerScrollBars((JScrollPane)((JViewport)this.getParent()).getParent());
        }
        
        g.setColor(Color.white);
        g.fillRect(0, 0, dimReal.width, dimReal.height);
        //g.setColor(Color.black); g.fillOval(0, 0, dimReal.width, dimReal.height);
        oView.drawViewFactory(g); //4 Render the structure and images inside it.
    }

    public boolean setNewView(View oView){
        if(this.oView!=null){
            this.oView.clearView();
            this.removeAll();
            if(this.aoFunctionalities!=null && this.aoFunctionalities.keySet()!=null){
                Set<String> s = this.aoFunctionalities.keySet();
                for (Iterator it=s.iterator(); it.hasNext(); )
                    this.aoFunctionalities.get((String)it.next()).removeAll();
                this.aoFunctionalities.clear();
            }
        }
        this.oView = oView;
        oView.update(null, null);
        //oView.update(null, null);
        this.addFunctionalities();
        this.setVisible(true);
        return true;
    }

    public void computeTime(){
        long tempoInicial = System.currentTimeMillis();
        long tempoFinal = System.currentTimeMillis();
        System.out.println( "Tempo de execução  em ViewComposed ->" + ((tempoFinal - tempoInicial)*0.001)+ " segundos" );
    }
        
    public void changePnl(PnlView newpnl){
         this.oView=newpnl.oView;
         this.aoFunctionalities=newpnl.aoFunctionalities;
    }

    public boolean isHasComponentChanged() {
        return hasComponentChanged;
    }

    public void setHasComponentChanged(boolean hasComponentChanged) {
        this.hasComponentChanged = hasComponentChanged;
    }
    
    @Override
    public void printWithGraphics(Graphics g) {
        paintComponent(g);
    }

    // ******************* Functionalities *************************************
        public void addFunctionalities(){
        aoFunctionalities=new HashMap<String,Functionality>();
        aoFunctionalities.put("Zoom",new FunZoom(oView,this));
        aoFunctionalities.put("Options",new FunOptions(oView,this));
        aoFunctionalities.put("DetailsOnDemand",new FunDetailsOnDemand(oView,this));
        //aoFunctionalities.add(new FunDragDrop(oView,this));
        //aoFunctionalities.add(new FunHierarquical(oView,this));
        //aoFunctionalities.add(new DecZoom(oView,this));
    }

    public void addFunctionality(String key, Functionality pFunctionality){
        this.aoFunctionalities.put(key,pFunctionality);
    }

    public Functionality getFunctionality(String key){
        return (Functionality)aoFunctionalities.get(key);
    }

    // ******************* Getters and Setters *********************************
    public View getoView() {        return oView;    }
    public void setoView(View oView) {        this.oView = oView;    }
    // *************************************************************************

    /**
     * Rigthnow swing supports double buffer, but it was necessary with awt
     */
    public void unusedDoubleBuffer(Dimension dimRealFinal){
        Image oImageOffscreen = null;
        Graphics oGraphicsOff = null;
        Dimension oDimOffscreen;
        if(oImageOffscreen==null)   oImageOffscreen = createImage(dimRealFinal.width, dimRealFinal.height);
        if(oGraphicsOff!=null)      oGraphicsOff.dispose();
        oGraphicsOff = oImageOffscreen.getGraphics();

        oGraphicsOff.setColor(Color.darkGray);
        oGraphicsOff.fillRect(0, 0, dimRealFinal.width, dimRealFinal.height);
        oGraphicsOff.setColor(Color.black);
        oGraphicsOff.fillOval(0,0,dimRealFinal.width, dimRealFinal.height);
        oView.drawViewFactory(oGraphicsOff);//4
        //******Finally the USED IMAGE is drawed into the actual screen*******//
        //boolean bTeste = g.drawImage(oImageOffscreen, 0, 0, dimRealFinal.width, dimRealFinal.height, null);
    }

}
